/**
 * Copyright 2011-2011 - Members of the Chaupal Community
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package net.chaupal.Impl.v1.Proof.ConfirmationProtocol;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public final class CombinedSequences {

    private HashMap<String,CPSequence> combinedSequences
        = new HashMap<String,CPSequence>();

    private ArrayList<CPSequence> aliceSeqs;
    private ArrayList<CPSequence> bobSeqs;

    public CombinedSequences() {

        AliceSequences alice = new AliceSequences();
        BobSequences bob = new BobSequences();

        aliceSeqs = alice.getSequences();
        bobSeqs = bob.getSequences();

    }

    private FileReader seqFR = null;

    public void load() throws FileNotFoundException, IOException {

        seqFile = new File("Sequences.txt");
        seqFR = new FileReader(seqFile);
        BufferedReader BR = new BufferedReader(seqFR);

        String tmp = BR.readLine();
        while ( tmp != null ) {
            combinedSequences.put(tmp, new CPAnalysis(tmp));
            tmp = BR.readLine();
        }

    }

    public HashMap<String,CPAnalysis> getAnalysisBase() {

        HashMap<String,CPAnalysis> result = new HashMap<String,CPAnalysis>();

        for (CPSequence item : combinedSequences.values()) {
            result.put(item.getShortCode(), new CPAnalysis(item));
        }

        return result;
        
    }

    public void generateSequences() {

        try {
            seqFile = new File("Sequences.txt");
            if ( seqFile.exists() ) {
                seqFile.delete();
            }
            seqFW = new FileWriter(seqFile);
        } catch (IOException ex) {
            System.err.println(ex);
        }

        for ( CPSequence aItem : aliceSeqs ) {
            registerCombinedSequence(aItem.getShortCode(), aItem);
            for ( CPSequence bItem : bobSeqs ) {
                registerCombinedSequence(bItem.getShortCode(), bItem);
                for ( CPSequence combItem : generateCombinedSequences(aItem, bItem) ) {
                    registerCombinedSequence(combItem.getShortCode(), combItem);
                }
            }
        }

        try {
            seqFW.close();
        } catch (IOException ex) {
            System.err.println(ex);
        }

    }

    private File seqFile;
    private FileWriter seqFW;

    private void registerCombinedSequence(String SC, CPSequence CPan) {

        if ( !combinedSequences.containsKey(SC) ) {
            combinedSequences.put(SC, CPan);
            String tmp = SC + "\n";
            try {
                seqFW.write(tmp);
            } catch (IOException ex) {
                System.err.println(ex);
            }
        }

    }

    public ArrayList<CPSequence> getCombinedSequences() {
        return new ArrayList<CPSequence>(combinedSequences.values());
    }

    public static ArrayList<CPSequence> generateCombinedSequences(
            CPSequence alice, CPSequence bob) {

        // Preparing result
        ArrayList<CPSequence> result = new ArrayList<CPSequence>();
        result.add(alice);

        for (CPEvent item : bob.getSequence()) {
            ArrayList<CPSequence> tmp = new ArrayList<CPSequence>();
            for (CPSequence seq : result.toArray(new CPSequence[0])) {
                tmp.addAll(addOneEvent(item,seq));
            }
            result = tmp;
        }

        // Returning result
        return result;

    }

    public static ArrayList<CPSequence> addOneEvent(CPEvent a, CPSequence seq) {

        // Preparing result
        ArrayList<CPSequence> result = new ArrayList<CPSequence>();

        CPEvent[] x = seq.getSequence();
        int tmp = 1 + x.length;

        CPEvent[] tmpSeq = new CPEvent[tmp];
        tmpSeq[0] = a;
        for (int i=1;i<tmp;i++)
            tmpSeq[i] = x[i-1];

        result.add(new CPSequence(tmpSeq));
        for (int i=0;i<x.length;i++) {
            CPEvent tmptmp = tmpSeq[i];
            tmpSeq[i] = tmpSeq[i+1];
            tmpSeq[i+1] = tmptmp;
            result.add(new CPSequence(tmpSeq));
        }

        return result;

    }

}